﻿// -----------------------------------------------------------------------
// <copyright file="MATLAPOper.cs" company="Fcis">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace IP_Package.Operations.MATLAP_operations
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Linq;
    using System.Text;
    using FrequencyDomain;
    using IPPackage;
    using MathWorks.MATLAB.NET.Arrays;
    using MathWorks.MATLAB.NET.Utility;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class MATLAPOper : IPPackage.ImageOperation.Open 
    {
        /// <summary>
        /// object to use comman methods insert HistoOperation
        /// </summary>
        private Global_applications.Global_methods_user useMethod = new Global_applications.Global_methods_user();

        /// <summary>
        /// object of matlap class
        /// </summary>
        private FrequencyDomain newFreqDomain;

        /// <summary>
        /// real result from convert from spatial to frequence to special color
        /// </summary>
       private double[,] arrRealOfSpecialColor;

      /// <summary>
      /// imagian result from convert from spatial to frequence to special color
      /// </summary>
      private double[,] arrImagOfSpecialColor;

      /// <summary>
      /// real result from convert from spatial to frequence
      /// </summary>
      private double[,,] arrReal;

      /// <summary>
      /// imagian result from convert from spatial to frequence
      /// </summary>
      private double[,,] arrImag;

       /// <summary>
       /// result of magnitude of frequency signal in determine color
       /// </summary>
      private double[,] resultMagofSpecialColor;

      /// <summary>
      /// result of magnitude in each color
      /// </summary>
        private double[,,] resultMagForEachColor;

       /// <summary>
       /// red result
       /// </summary>
      private byte[,] selectedColorValue;

      /// <summary>
      /// Initializes a new instance of the <see cref="MATLAPOper"/> class.
      /// </summary>
      public MATLAPOper()
      {
          try
          {
              this.newFreqDomain = new FrequencyDomain();
          }
          catch (Exception ex)
          {
              Logger.LogException(ex);
          }
      }

        /// <summary>
        /// Calcus the color of the magnitude TO detemine color.
        /// </summary>
        /// <param name="color">The color need magnitude of it.</param>
        /// <returns>new image of red</returns>
        public Bitmap CalcuMagnitudeTODetemineColor(string color)
        {
            try
            {
                this.CalcuRealAndImagianToSpeficalColor(color);
            }
            catch
            {
                throw;
            }

            try
            {
                this.resultMagofSpecialColor = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
                for (int i = 0; i < this.arrRealOfSpecialColor.GetLength(1); i++)
                {
                    for (int j = 0; j < this.arrRealOfSpecialColor.GetLength(0); j++)
                    {
                        this.resultMagofSpecialColor[j, i] = Math.Sqrt(Math.Pow(this.arrRealOfSpecialColor[j, i], 2) + Math.Pow(this.arrImagOfSpecialColor[j, i], 2));
                        this.resultMagofSpecialColor[j, i] = Math.Log(this.resultMagofSpecialColor[j, i] + 1);
                    }
                }
            }
            catch (Exception ex) 
            {
                Logger.LogException(ex);
                throw;
            }

            try
            {
                this.useMethod.BufferOfImage = this.BufferOfImage;
                Bitmap resultImg = this.useMethod.Normalization(color, this.resultMagofSpecialColor);
                this.NewBufferOfImage = this.useMethod.NewBufferOfImage;
                return resultImg;
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// convert the frequency domain to spatial domain.
        /// </summary>
        /// <returns>new image in spatial domain</returns>
        public Bitmap ConvertToSpatialDomain()
        {
            try
            {
                Bitmap newIMagFre = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
                this.CalcuRealAndImagianToSpeficalColor("Red");
                MWArray returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] redSpatial = (double[,])returnedMatrix.ToArray();
                this.CalcuRealAndImagianToSpeficalColor("Green");
                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] greenSpatial = (double[,])returnedMatrix.ToArray();
                this.CalcuRealAndImagianToSpeficalColor("Blue");
                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] blueSpatial = (double[,])returnedMatrix.ToArray();
                Bitmap newImg = new Bitmap(blueSpatial.GetLength(0), blueSpatial.GetLength(1));
                for (int i = 0; i < blueSpatial.GetLength(1); i++)
                {
                    for (int j = 0; j < blueSpatial.GetLength(0); j++)
                    {
                        this.BufferOfImage[j, i] = Color.FromArgb((byte)redSpatial[j, i], (byte)greenSpatial[j, i], (byte)blueSpatial[j, i]);
                        newImg.SetPixel(j, i, this.BufferOfImage[j, i]);
                    }
                }

                return newImg;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Converts to spatial domain v2.
        /// </summary>
        /// <param name="valuesReal">The values real.</param>
        /// <param name="valuesImg">The values img.</param>
        public void ConvertToSpatialDomainV2(double[,,] valuesReal, double[,,] valuesImg)
        {
            try
            {
                for (int i = 0; i < valuesImg.GetLength(1); i++)
                {
                    for (int j = 0; j < valuesImg.GetLength(0); j++)
                    {
                        this.arrImagOfSpecialColor[j, i] = valuesImg[j, i, 0];
                        this.arrRealOfSpecialColor[j, i] = valuesReal[j, i, 0];
                    }
                }

                MWArray returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] redSpatial = (double[,])returnedMatrix.ToArray();
                for (int i = 0; i < valuesImg.GetLength(1); i++)
                {
                    for (int j = 0; j < valuesImg.GetLength(0); j++)
                    {
                        this.arrImagOfSpecialColor[j, i] = valuesImg[j, i, 1];
                        this.arrRealOfSpecialColor[j, i] = valuesReal[j, i, 1];
                    }
                }

                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] greenSpatial = (double[,])returnedMatrix.ToArray();
                for (int i = 0; i < valuesImg.GetLength(1); i++)
                {
                    for (int j = 0; j < valuesImg.GetLength(0); j++)
                    {
                        this.arrImagOfSpecialColor[j, i] = valuesImg[j, i, 2];
                        this.arrRealOfSpecialColor[j, i] = valuesReal[j, i, 2];
                    }
                }

                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] blueSpatial = (double[,])returnedMatrix.ToArray();
                Bitmap newImg = new Bitmap(blueSpatial.GetLength(0), blueSpatial.GetLength(1));
                for (int i = 0; i < blueSpatial.GetLength(1); i++)
                {
                    for (int j = 0; j < blueSpatial.GetLength(0); j++)
                    {
                        valuesReal[j, i, 0] = redSpatial[j, i];
                        valuesReal[j, i, 1] = greenSpatial[j, i];
                        valuesReal[j, i, 2] = blueSpatial[j, i];
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Calcus the magnitude TO imag.
        /// </summary>
        /// <returns>magnitude of this image</returns>
        public Bitmap CalcuMagnitudeTOImag()
        {
            this.CalcuRealAndImagian();
            try
            {
                this.resultMagForEachColor = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), 3];
                for (int i = 0; i < this.arrReal.GetLength(1); i++)
                {
                    for (int j = 0; j < this.arrReal.GetLength(0); j++)
                    {
                        this.resultMagForEachColor[j, i, 0] = Math.Sqrt(Math.Pow(this.arrReal[j, i, 0], 2) + Math.Pow(this.arrImag[j, i, 0], 2));
                        this.resultMagForEachColor[j, i, 0] = Math.Log(this.resultMagForEachColor[j, i, 0] + 1);
                        this.resultMagForEachColor[j, i, 1] = Math.Sqrt(Math.Pow(this.arrReal[j, i, 1], 2) + Math.Pow(this.arrImag[j, i, 1], 2));
                        this.resultMagForEachColor[j, i, 1] = Math.Log(this.resultMagForEachColor[j, i, 1] + 1);
                        this.resultMagForEachColor[j, i, 2] = Math.Sqrt(Math.Pow(this.arrReal[j, i, 2], 2) + Math.Pow(this.arrImag[j, i, 2], 2));
                        this.resultMagForEachColor[j, i, 2] = Math.Log(this.resultMagForEachColor[j, i, 2] + 1);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }

            this.useMethod.BufferOfImage = this.BufferOfImage;
            Bitmap resultImg = this.useMethod.Normalization(this.resultMagForEachColor);
            this.NewBufferOfImage = this.useMethod.NewBufferOfImage;
            return resultImg;
        }

        /// <summary>
        /// Calculte image of pass filter.
        /// </summary>
        /// <param name="typeOfPass">The type of pass.</param>
        /// <param name="typeOfMask">The type of mask.</param>
        /// <param name="d0">The d0.</param>
        /// <param name="order">The order.</param>
        /// <returns>new image.</returns>
        public Bitmap CalcuTOIMGPass(string typeOfPass, string typeOfMask, double d0, double order)
        {
            FilterMaskCalc newMask = new FilterMaskCalc();
            double[,] h = newMask.CalcFilterMaskToImage(typeOfPass, typeOfMask, this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), d0, order);
            this.CalcuRealAndImagian();
            double[,,] resultBeforeNormalizationReal = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), 3];
            double[,,] resultBeforeNormalizationImag = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), 3];
            for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
            {
                for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                {
                    resultBeforeNormalizationReal[j, i, 0] = this.arrReal[j, i, 0] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 1] = this.arrReal[j, i, 1] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 2] = this.arrReal[j, i, 2] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 0] = this.arrImag[j, i, 0] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 1] = this.arrImag[j, i, 1] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 2] = this.arrImag[j, i, 2] * h[j, i];
                }
            }

            this.ConvertToSpatialDomainV2(resultBeforeNormalizationReal, resultBeforeNormalizationImag);
            this.useMethod.BufferOfImage = this.BufferOfImage;
            Bitmap resultImg = this.useMethod.Normalization(resultBeforeNormalizationReal);
            this.NewBufferOfImage = this.useMethod.NewBufferOfImage;
            return resultImg;
        }

        /// <summary>
        /// Calculte image of pass filter.
        /// </summary>
        /// <param name="typeOfPass">The type of pass.</param>
        /// <param name="typeOfMask">The type of mask.</param>
        /// <param name="d0">The d0.</param>
        /// <param name="order">The order.</param>
        /// <param name="uc">The uc.</param>
        /// <param name="vc">The vc.</param>
        /// <returns>
        /// new image.
        /// </returns>
        public Bitmap CalcuTOIMGPass(string typeOfPass, string typeOfMask, double d0, double order, double uc, double vc)
        {
            FilterMaskCalc newMask = new FilterMaskCalc();
            double[,] h = newMask.CalcFilterMaskToImage(typeOfPass, typeOfMask, this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), d0, uc, vc);
            this.CalcuRealAndImagian();
            double[,,] resultBeforeNormalizationReal = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), 3];
            double[,,] resultBeforeNormalizationImag = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), 3];
            for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
            {
                for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                {
                    resultBeforeNormalizationReal[j, i, 0] = this.arrReal[j, i, 0] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 1] = this.arrReal[j, i, 1] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 2] = this.arrReal[j, i, 2] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 0] = this.arrImag[j, i, 0] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 1] = this.arrImag[j, i, 1] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 2] = this.arrImag[j, i, 2] * h[j, i];
                }
            }

            this.ConvertToSpatialDomainV2(resultBeforeNormalizationReal, resultBeforeNormalizationImag);
            this.useMethod.BufferOfImage = this.BufferOfImage;
            Bitmap resultImg = this.useMethod.Normalization(resultBeforeNormalizationReal);
            this.NewBufferOfImage = this.useMethod.NewBufferOfImage;
            return resultImg;
        }

        /// <summary>
        /// Calcus the real and imagian of special color.
        /// </summary>
        /// <param name="color">The color need magnitude of it.</param>
        private void CalcuRealAndImagianToSpeficalColor(string color)
        {
            try
            {
                this.selectedColorValue = new byte[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        if (color == "Red" || color == "red")
                        {
                            this.selectedColorValue[j, i] = this.BufferOfImage[j, i].R;
                        }
                        else if (color == "green" || color == "Green")
                        {
                            this.selectedColorValue[j, i] = this.BufferOfImage[j, i].G;
                        }
                        else
                        {
                            this.selectedColorValue[j, i] = this.BufferOfImage[j, i].B;
                        }
                    }
                }

                MWArray[] returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)this.selectedColorValue);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
            }
            catch (Exception ex) 
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Calcus the real and imagian of iamge.
        /// </summary>
        private void CalcuRealAndImagian()
        {
            try
            {
                double[,] valueOfImage = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
               this.arrImag = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), 3];
               this.arrReal = new double[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1), 3];
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        valueOfImage[j, i] = (double)this.BufferOfImage[j, i].R;
                    }
                }

                MWArray[] returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)valueOfImage);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        this.arrReal[j, i, 0] = this.arrRealOfSpecialColor[j, i];
                        this.arrImag[j, i, 0] = this.arrImagOfSpecialColor[j, i];
                        valueOfImage[j, i] = this.BufferOfImage[j, i].G;
                        ////valueOfImage[j, i] = this.BufferOfImage[j, i].B;
                    }
                }

                returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)valueOfImage);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        this.arrReal[j, i, 1] = this.arrRealOfSpecialColor[j, i];
                        this.arrImag[j, i, 1] = this.arrImagOfSpecialColor[j, i];
                        valueOfImage[j, i] = this.BufferOfImage[j, i].B;
                    }
                }

                returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)valueOfImage);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        this.arrReal[j, i, 2] = this.arrRealOfSpecialColor[j, i];
                        this.arrImag[j, i, 2] = this.arrImagOfSpecialColor[j, i];
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }
    }
}
